Beginners Programming
Demos
Lets Play
I know we have covered quite a bit of ground already, but we have just a couple more new subjects to introduce so that we can complete our game. Let's begin by reviewing the NOTICE and CONFIRM functions in Liberty Basic. We will be using these to add our ABOUT window and our brief HELP window, both of which are triggered by buttons on the game window.
We spent a lot of time with both of these commands a few issues back. As you will recall (I hope) the NOTICE function displays a text message in a messagebox with a single OK button. The CONFORM function also displays a message in a messagebox, but it has a YES and a NO button, allowing the user to make a choice. From the Liberty Basic Helpfile, we read the following about the NOTICE function:
This command pops up a dialog box which displays "string expression"
and which has a button OK which the user presses after the message is
read. Pressing Enter also closes the dialog box.
Two forms are allowed. If "string expression" has no Cr character
(ASCII 13), then the title of the dialog box will be 'Notice' and
"string expression" will be the message displayed inside the dialog
box. If "string expression" does have a Cr character, then the part
of "string expression" before Cr will be used as the title for the
dialog box, and the part of "string expression" after Cr will be
displayed as the message inside. Further Cr's will force line breaks
into the text contained in the message.
Usage:
notice "Super Stats is Copyright 2001, Mathware"
Or:
notice "Fatal Error!" + chr$(13) + "The entry buffer is full!"
Personally I like to build my notice text string by loading it into a string variable (a buffer) and then use the NOTICE function with the string variable as the argument. This allows me to create fairly long, yet somewhat controlled strings of data. Pass the function a carriage return (ASCII 13) to create line breaks and make multi-line notice windows. Be aware that the first bit of text before the first carriage return will become the messagebox's caption.
You can create a long string by continually appending additional text to an existing string, as in this example:
A$ = "The big brown cow" A$ = A$ + " jumped over the moon"
This will combine both strings, creating the string:
"The big brown cow jumped over the moon"
There is another way to do this, and I often use this method when building a large text buffer to be passed to a print statement, notice function or confirm function. That is to bend a single line of code over multiple lines. This is done with the line continuation character. The line continuation character is an underscore "_" in Liberty Basic, and when it appears as the very last character on a line of text, it causes Liberty Basic's interpreter to link the next line with the current line, treating them as a single line. You can use these continuation characters to link several, even many lines of text together. Here is an example:
A$ = "The big red dog laughed to see the sight " + _
"and the knife ran away with the spoon."
Notice that I still added the strings together. I was required to terminate the text string BEFORE using the continuation character. The continuation character is ignored if enclosed in a text string (even if the end of the text string is left unterminated by quotations). This meant that I actually had two text strings and I needed to combine them - this can be done with a simple plus sign. The code above will produce:
"The big red dog laughed to see the sight and the knife ran away with the spoon."
The CONFIRM function is very similar to the NOTICE function. It allows multiple line of text and you can pass it a text buffer in the form of a string like the NOTICE function. The exceptions are: The caption of the CONFIRM window is fixed. You can not set it the same as the NOTICE window - the first carriage return in the text buffer passed to it will merely separate the first line of text from the second. The other difference is that the function will return a value. Depending on which button the user clicks, the function (and it is a function because it returns a value) will return either a "yes" or a "no" string value. Here is how the Liberty Basic help file puts it:
CONFIRM string; responseVar Description: This statement opens a dialog box displaying the contents of string and presenting two buttons marked 'Yes' and 'No'. When the selection is made, the string "yes" is returned if 'Yes' is pressed, and the string "no" is returned if 'No' is pressed. The result is placed in responseVar. Usage: [quit] ' bring up a confirmation box to be sure that ' the user wants to quit confirm "Are you sure you want to QUIT?"; answer$ if answer$ = "no" then [mainLoop] end
The final item I want to introduce, before we can finish the game, is the SUB program. Until now we have created routines that we use GOTO and GOSUB to call. These routines are always denoted with a label which is enclosed in brackets "[ ]". We consider these routines to be inline with the program code. The SUB program is very similar to the routines we have created so far, except it is a neat little self contained program module which is NOT inline with the code. SUB programs are named and have the additional feature of being able to accept arguments that you specify. You do not use GOTO or GOSUB to execute the code in a SUB program; instead you CALL a SUB program. The SUB program (and its cousin the FUNCTION) are very powerful and have some unique features that make them very desirable over the basic routine. We will not be discussing or exploiting these more advanced features in this installment, but be aware these exist. Here is what the Liberty Basic Helpfile says about SUB program:
sub subName zero or more comma separated parameter variable names
'code for the sub goes in here
end sub
Description:
Define a subprogram. Zero or more parameters may be passed into the
subprogram. The variables names inside a subprogram are scoped locally,
meaning that the value of any variable is different from variables of
the same name outside of the subprogram. Arrays, structs and handles
of files, DLLs and windows are global to a Liberty BASIC program, and
visible inside of a subprogram without needing to be passed in.
Branch labels are also locally scoped. Code inside a sub cannot see
branch labels outside of the sub, and code outside a sub cannot see
branch labels inside any sub.
To use a subprogram, use the call statement to pass values into the
subprogram. The values you pass in must be the same type as the sub
statement defines them to be. So the following example:
sub mySubName string$, number, string2$
might be called like this:
call mySubName "string value", 123, str$("321")
A sub cannot contain another sub definition, nor a function definition.
Ending a Sub:
The sub definition must end with the expression: end sub
Don't be too confused by some of the information, especially the concepts of scope and passing arguments. We will get into these in a later installment. Do be aware that a SUB program must begin with the keyword SUB and must end with the END SUB keywords, creating a code block which is similar in concept to the code blocks enclosed in an IF-THEN-END IF code block.
We will be using the SUB program in our game to display the message box for the "About" button and also for the Help button. These will be two separate SUB programs. We will consider the "About" function first. Up to this point we have not even created the event handler for the about command button (as well as Help and New Game). So, first the event handler - remember the event will be triggered when the user clicks the "About" button. The code we used to set up the button in the main window looked like this:
button #main.about, "About",[about],UL, 240, 100, 100, 25
The portion in brackets is the name (or label) of our event handler. This label must appear somewhere in our code, or clicking on the button will cause an error. This is what that code looks like. It can appear after the after the WAIT statement.
[about]
call aboutGC
wait
Notice that I have used the CALL statement to call a SUB program called "aboutGC". That SUB program must also appear in the code somewhere. As an additional note on the operation of the CALL statement, it will cause the program to begin executing the code in the SUB program, but once the END SUB statement is encountered, the program execution will return to the next statement after the CALL which was invoked. In the case of our code above, that would be the WAIT statement. So in this manner it is a bit like the GOSUB statement.
Now the "aboutGC" SUB program:
sub aboutGC
a$ = "About GraphicCraps..." + chr$(13)
a$ = a$ + "Graphic Craps - for Liberty Basic" + chr$(13)
a$ = a$ + "by Brad Moore, 2004" + chr$(13) + chr$(13)
a$ = a$ + "released into the Public Domain" + chr$(13) + chr$(13)
a$ = a$ + "Learn about Liberty Basic by visiting:" + chr$(13)
a$ = a$ + "http://www.libertybasic.com" + chr$(13) + chr$(13)
a$ = a$ + "See the Liberty Basic Newsletter online at:" + chr$(13)
a$ = a$ + "http://babek.info/libertybasicfiles/lbnews/" + chr$(13) + chr$(13)
a$ = a$ + "Have FUN!"
notice a$
end sub
I hope you recognize the buffer that I am building in the SUB program. I start with a$ and slowly, line by line add more string text to the buffer. Each line is terminated by a carriage return (the ASCII 13) which is added with the chr$(13) statement. Notice also that the first text string added to the a$, just before the first chr$(13) statement will be the message box's caption. In our case it will be "About GraphicCraps". Just before the SUB program ends the NOTICE function is executed. Add this code to the end of you program, run the program and click the "About" button.
The "Help" button follows the same format. Add the event handler for "Help" just below the event handler for "About".
[help]
call helpGC
wait
Now add the SUB program for "helpGC" which is nearly identical to the "aboutGC" SUB program.
sub helpGC
a$ = "HELP for GraphicCraps..." + chr$(13)
a$ = a$ + "Here are the basic rules we will be using: Two dice are used." + chr$(13)
a$ = a$ + "Initial roll of the dice is to establish the 'point' which you" + chr$(13)
a$ = a$ + "will be trying to roll again. Rolling a 7 or 11 with your first" + chr$(13)
a$ = a$ + "roll is an automatic win. Rolling a 2, 3 or 12 with your initial" + chr$(13)
a$ = a$ + "roll is an automatic loss. An initial roll of 4, 5, 6, 8, 9 or" + chr$(13)
a$ = a$ + "10 establishes the 'point'." + chr$(13) + chr$(13)
a$ = a$ + "Once a point is established the player must roll the dice again" + chr$(13)
a$ = a$ + "(repeatedly until they win or lose). Rolling the 'point' again" + chr$(13)
a$ = a$ + "is a win. Rolling a 7 is a loss. Have fun!" + chr$(13)
notice a$
end sub
This leaves the "New Game" function. I chose not to use a SUB program for this one. It is a basic event handler with all code inline. The event handler uses a CONFIRM function to determine whether the user really wants to start the game over or not. Starting the game over simply resets the win/loss statistics and if the game is in phase two, it is reset into phase one. Here is the code to do this:
[new]
confirm "Begin a New Game?" + chr$(13) + _
"This will reset win/loss results." + chr$(13) + _
"Are you sure you want to do this?"; answer$
if answer$ = "no" then wait
phase = 1
wins = 0
losses = 0
#main.info "Beginning New Game - Click to start"
#main.point "Point has not been made yet"
#main.wins "Wins = 0"
#main.losses "Losses = 0"
#main.roll, "Start Round"
wait
Add this code to your program by pasting it below the event handler for "Help". Notice that I have user the line continuation technique in the CONFIRM function. In addition, I have not built a buffer this time, but simply created the text string as the CONFIRM argument. It can be done either way - as shown here, or by creating a string buffer (like I did for "About" and "Help") and then passing the string as the functions argument.
Remember that the CONFIRM function returns a string in the second argument. In the case of my routine, I have chosen answer$ to hold the response that the user selected. It will contain a "yes", a "no" or even an empty string if the user closed the window without selecting a response. I have decided that all responses except "no" will mean "YES - I want to start a new game". If the user selects "no" the code simply starts to WAIT again for the next even. Otherwise, the game is reset by returning the tracking variables to their original values and resetting the labels and captions of buttons. The result is a new game!
If you have Liberty Basic version 3.03 or higher, there is one more item you can add to the game to make it a little more playable. That is the randomize statement. This statement simply reseeds the random number generator to produce a set stream of random values. It takes a fractional number greater than zero and less than one as its only argument. Here is what the Liberty Basic Helpfile says about it:
RANDOMIZE n Seed the random number generator in a predictable way. The seed numbers should be greater than 0 and less than 1. Numbers such as 0.01 and 0.95 should be used with RANDOMIZE.
I like to give it a small number created by dividing the current number of milliseconds since midnight with the value 86400000 (which is the total possible milliseconds in a 24 hour period). It always produces a fractional value less than 1. I use the TIME$ function to get the number of milliseconds since midnight. You can look that up in the Liberty Basic Helpfile, or wait until we review it in a later installment. Here is the code - place it at the top of your program:
'make the game truly random by seeding the generator
RANDOMIZE time$("ms")/86400000
This completes the GraphicCraps game. You can see the full listing in Appendix B, or it is included in bas form along with the sound file used (a wav file) by the game in the newsletter archive.
Looking Ahead
Our next challenge leverages the stuff we have learned here and something new. It will require that you did a little bit through the Liberty Basic Helpfile to complete. I highly recommend trying to complete these challenges, as they stretch your programming experience and help you learn to think like a programmer. It is ok if you do not create the same program I do later, the important thing is trying.
In this challenge I want you to use buttons, a standard window and a new control we have not mentioned called a Textbox to create a calculator. This new project will look something like this:

Obviously this is not a game, but a very good platform to practice handling events and controls. We will also be examining FreeForm in a bit more detail next time. I recommend you play around with it, take a look at the Helpfile and see what you can come up with. To get you started, here is what the Helpfile says about the Textbox:
The textbox command lets you add a single item, single line text entry/editor box to your windows. It is useful for generating forms in particular.
The syntax for textbox is simply:
TEXTBOX #handle.ext, xpos, ypos, wide, high #handle.ext - The #handle part must be the same as for the window you are adding the textbox to. The .ext part must be unique for the textbox. xpos & ypos - This is the position of the textbox in x and y from the upper-left corner of the window. wide & high - This is the width and height of the textbox in pixels.
Be aware that the Textbox accepts commands just like the Statictext control does, although there are more valid commands for Textbox than for Statictext.
Until next time: Have fun...